package cloud.topdaddy.admin.login.service;

import cn.dev33.satoken.model.wrapperInfo.SaDisableWrapperInfo;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cloud.topdaddy.admin.login.entity.LoginEntity;
import cloud.topdaddy.admin.system.entity.SysUser;
import cloud.topdaddy.admin.system.service.SysUserService;
import cloud.topdaddy.admin.system.service.SysUserRoleService;
import cloud.topdaddy.admin.system.service.SysRoleService;
import cloud.topdaddy.admin.system.service.SysRoleMenuService;
import cloud.topdaddy.admin.system.service.SysMenuService;
import cloud.topdaddy.base.common.resp.R;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;

/**
 * 登录服务
 *
 * @author topdaddy
 * @since 2023-03-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LoginService implements StpInterface {

    private final SysUserService sysUserService;
    private final SysUserRoleService sysUserRoleService;
    private final SysRoleService sysRoleService;
    private final SysRoleMenuService sysRoleMenuService;
    private final SysMenuService sysMenuService;

    public R<Map<String, Object>> login(LoginEntity loginEntity, HttpSession session) {
        if (loginEntity == null
                || StringUtils.isBlank(loginEntity.getUsername())
                || StringUtils.isBlank(loginEntity.getPassword())
                || StringUtils.isBlank(loginEntity.getCaptcha())) {
            return R.userErrorParam("用户名、密码或验证码不能为空");
        }
        String storedCaptcha = session != null ? (String) session.getAttribute("captcha") : null;
        if (StringUtils.isBlank(storedCaptcha) || !storedCaptcha.equalsIgnoreCase(loginEntity.getCaptcha())) {
            return R.userErrorParam("验证码错误或已失效");
        }
        if (session != null) {
            session.removeAttribute("captcha");
        }
        SysUser user = sysUserService.lambdaQuery()
                .eq(SysUser::getUsername, loginEntity.getUsername())
                .one();
        if (user == null) {
            return R.userErrorParam("用户名或密码错误");
        }
        if (Boolean.TRUE.equals(user.getIsDeleted())) {
            return R.userErrorParam("账号已删除");
        }
        if (Boolean.TRUE.equals(user.getLockFlag())) {
            return R.userErrorParam("账号已禁用");
        }
        String raw = loginEntity.getPassword();
        String stored = user.getPassword();
        boolean match = false;
        if (stored != null) {
            if (stored.startsWith("$2a$") || stored.startsWith("$2b$") || stored.startsWith("$2y$")) {
                match = new BCryptPasswordEncoder().matches(raw, stored);
            } else {
                match = raw.equals(stored);
            }
        }
        if (!match) {
            return R.userErrorParam("用户名或密码错误");
        }

        StpUtil.login(user.getUserId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        Map<String, Object> data = Map.of(
                "tokenName", tokenInfo.getTokenName(),
                "tokenValue", tokenInfo.getTokenValue(),
                "loginId", tokenInfo.getLoginId()
        );
        return R.ok(data);
    }

    @Override
    @Cacheable(cacheNames = "auth:perms#10m", key = "T(java.lang.String).valueOf(#loginId)")
    public List<String> getPermissionList(Object loginId, String loginType) {
        try {
            Long uid = Long.valueOf(String.valueOf(loginId));
            var userRoles = sysUserRoleService.lambdaQuery()
                    .eq(cloud.topdaddy.admin.system.entity.SysUserRole::getUserId, uid)
                    .list();
            if (userRoles == null || userRoles.isEmpty()) return List.of();
            var roleIds = userRoles.stream().map(cloud.topdaddy.admin.system.entity.SysUserRole::getRoleId).toList();
            var roleMenus = sysRoleMenuService.lambdaQuery()
                    .in(cloud.topdaddy.admin.system.entity.SysRoleMenu::getRoleId, roleIds)
                    .list();
            if (roleMenus == null || roleMenus.isEmpty()) return List.of();
            var menuIds = roleMenus.stream().map(cloud.topdaddy.admin.system.entity.SysRoleMenu::getMenuId).distinct().toList();
            var menus = sysMenuService.lambdaQuery()
                    .in(cloud.topdaddy.admin.system.entity.SysMenu::getMenuId, menuIds)
                    .eq(cloud.topdaddy.admin.system.entity.SysMenu::getDeletedFlag, false)
                    .eq(cloud.topdaddy.admin.system.entity.SysMenu::getDisabledFlag, false)
                    .list();
            if (menus == null || menus.isEmpty()) return List.of();
            return menus.stream()
                    .map(cloud.topdaddy.admin.system.entity.SysMenu::getApiPerms)
                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                    .distinct()
                    .toList();
        } catch (Exception e) {
            log.warn("getPermissionList error, loginId={}", loginId, e);
            return List.of();
        }
    }

    @Override
    @Cacheable(cacheNames = "auth:roles#10m", key = "T(java.lang.String).valueOf(#loginId)")
    public List<String> getRoleList(Object loginId, String loginType) {
        try {
            Long uid = Long.valueOf(String.valueOf(loginId));
            var userRoles = sysUserRoleService.lambdaQuery()
                    .eq(cloud.topdaddy.admin.system.entity.SysUserRole::getUserId, uid)
                    .list();
            if (userRoles == null || userRoles.isEmpty()) return List.of();
            var roleIds = userRoles.stream().map(cloud.topdaddy.admin.system.entity.SysUserRole::getRoleId).toList();
            var roles = sysRoleService.lambdaQuery()
                    .in(cloud.topdaddy.admin.system.entity.SysRole::getRoleId, roleIds)
                    .list();
            if (roles == null || roles.isEmpty()) return List.of();
            return roles.stream()
                    .map(cloud.topdaddy.admin.system.entity.SysRole::getRoleCode)
                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                    .distinct()
                    .toList();
        } catch (Exception e) {
            log.warn("getRoleList error, loginId={}", loginId, e);
            return List.of();
        }
    }

    @Override
    public SaDisableWrapperInfo isDisabled(Object loginId, String service) {
        return StpInterface.super.isDisabled(loginId, service);
    }
}
